agencja_nieruchomosci <- read.csv("agencja_nieruchomosci.csv")
knitr::kable(head(agencja_nieruchomosci, 10)) %>%
kable_styling(font_size = 10)| price | area | bedrooms | bathrooms | stories | mainroad | guestroom | basement | hotwaterheating | airconditioning | parking | prefarea | furnishingstatus |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NA | 7420 | 4 | 2 | 3 | NA | no | no | no | yes | 2 | yes | furnished |
| 12250000 | 8960 | 4 | 4 | 4 | yes | no | no | no | yes | 3 | no | furnished |
| 12250000 | 9960 | 3 | 2 | 2 | yes | no | yes | no | no | 2 | yes | semi-furnished |
| 12215000 | 7500 | 4 | 2 | 2 | yes | no | yes | no | yes | 3 | yes | furnished |
| 11410000 | 7420 | 4 | 1 | 2 | yes | yes | yes | no | yes | 2 | no | furnished |
| 10850000 | 7500 | 3 | 3 | 1 | yes | no | yes | no | yes | 2 | yes | semi-furnished |
| 10150000 | 8580 | 4 | 3 | 4 | yes | no | no | no | yes | 2 | yes | semi-furnished |
| 10150000 | 16200 | 5 | 3 | 2 | yes | no | no | no | no | 0 | no | unfurnished |
| 9870000 | 8100 | 4 | 1 | 2 | yes | yes | yes | no | yes | 2 | yes | furnished |
| 9800000 | 5750 | 3 | 2 | 4 | yes | yes | no | no | yes | 1 | yes | unfurnished |
Ogólne podsumowanie brakujących wartości
| variable | n_miss | pct_miss |
|---|---|---|
| price | 110 | 20.2 |
| mainroad | 50 | 9.17 |
| prefarea | 50 | 9.17 |
| area | 0 | 0 |
| bedrooms | 0 | 0 |
| bathrooms | 0 | 0 |
| stories | 0 | 0 |
| guestroom | 0 | 0 |
| basement | 0 | 0 |
| hotwaterheating | 0 | 0 |
| airconditioning | 0 | 0 |
| parking | 0 | 0 |
| furnishingstatus | 0 | 0 |
Wprowadzając podstawowe reguły, na przykład weryfikując czy cena nie
jest ujemna, mozemy zweryfikować sensowność naszych danych. Po
określeniu reguł są one upraszczane. Funkcja simplify_rules
pozwala sprawdzić czy nie ma w nich sprzeczności i wyeliminować
duplikaty. W tym przypadku wyczyszczenie reguł nie przyniosło zadnych
efektów.
rules <- validator(
price > 0 & price < 100000000,
area > 0 & area < 100000,
bedrooms > -1 & bedrooms < 10,
bathrooms > -1 & bathrooms < 10,
stories > -1 & stories < 20,
parking > -1 & parking < 5,
mainroad %in% c("yes", "no"),
guestroom %in% c("yes", "no"),
basement %in% c("yes", "no"),
hotwaterheating %in% c("yes", "no"),
airconditioning %in% c("yes", "no"),
prefarea %in% c("yes", "no"),
furnishingstatus %in% c(
"furnished",
"semi-furnished",
"unfurnished"
)
)
warnings()
validation_results <- confront(agencja_nieruchomosci, rules)
knitr::kable(summary(validation_results))| name | items | passes | fails | nNA | error | warning | expression |
|---|---|---|---|---|---|---|---|
| V01 | 545 | 435 | 0 | 110 | FALSE | FALSE | price > 0 & price < 1e+08 |
| V02 | 545 | 545 | 0 | 0 | FALSE | FALSE | area > 0 & area < 1e+05 |
| V03 | 545 | 545 | 0 | 0 | FALSE | FALSE | bedrooms > -1 & bedrooms < 10 |
| V04 | 545 | 545 | 0 | 0 | FALSE | FALSE | bathrooms > -1 & bathrooms < 10 |
| V05 | 545 | 545 | 0 | 0 | FALSE | FALSE | stories > -1 & stories < 20 |
| V06 | 545 | 545 | 0 | 0 | FALSE | FALSE | parking > -1 & parking < 5 |
| V07 | 545 | 495 | 0 | 50 | FALSE | FALSE | mainroad %vin% c(“yes”, “no”) |
| V08 | 545 | 545 | 0 | 0 | FALSE | FALSE | guestroom %vin% c(“yes”, “no”) |
| V09 | 545 | 545 | 0 | 0 | FALSE | FALSE | basement %vin% c(“yes”, “no”) |
| V10 | 545 | 545 | 0 | 0 | FALSE | FALSE | hotwaterheating %vin% c(“yes”, “no”) |
| V11 | 545 | 545 | 0 | 0 | FALSE | FALSE | airconditioning %vin% c(“yes”, “no”) |
| V12 | 545 | 495 | 0 | 50 | FALSE | FALSE | prefarea %vin% c(“yes”, “no”) |
| V13 | 545 | 545 | 0 | 0 | FALSE | FALSE | furnishingstatus %vin% c(“furnished”, “semi-furnished”, “unfurnished”) |
Funkcje summary i barplot zgodnie pokazują
ze wszystkie nasze dane mają realne wartości.
Aby ułatwić dalszą pracę można zmienić wartości binarne yes i no na 0 i 1. Wartościom z kolumny furnished nadajemy kolejno wartości 0, 1 i 2 (od unfurnished do furnished).
agencja_nieruchomosci$mainroad <-
ifelse(agencja_nieruchomosci$mainroad == "yes", 1, 0)
agencja_nieruchomosci$guestroom <-
ifelse(agencja_nieruchomosci$guestroom == "yes", 1, 0)
agencja_nieruchomosci$basement <-
ifelse(agencja_nieruchomosci$basement == "yes", 1, 0)
agencja_nieruchomosci$hotwaterheating <-
ifelse(agencja_nieruchomosci$hotwaterheating == "yes", 1, 0)
agencja_nieruchomosci$airconditioning <-
ifelse(agencja_nieruchomosci$airconditioning == "yes", 1, 0)
agencja_nieruchomosci$prefarea <-
ifelse(agencja_nieruchomosci$prefarea == "yes", 1, 0)
agencja_nieruchomosci$furnishingstatus <- ifelse(
agencja_nieruchomosci$furnishingstatus == "unfurnished",
0,
ifelse(
agencja_nieruchomosci$furnishingstatus == "semi-furnished",
1,
2
)
)
knitr::kable(head(agencja_nieruchomosci, 10)) %>%
kable_styling(font_size = 10)| price | area | bedrooms | bathrooms | stories | mainroad | guestroom | basement | hotwaterheating | airconditioning | parking | prefarea | furnishingstatus |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NA | 7420 | 4 | 2 | 3 | NA | 0 | 0 | 0 | 1 | 2 | 1 | 2 |
| 12250000 | 8960 | 4 | 4 | 4 | 1 | 0 | 0 | 0 | 1 | 3 | 0 | 2 |
| 12250000 | 9960 | 3 | 2 | 2 | 1 | 0 | 1 | 0 | 0 | 2 | 1 | 1 |
| 12215000 | 7500 | 4 | 2 | 2 | 1 | 0 | 1 | 0 | 1 | 3 | 1 | 2 |
| 11410000 | 7420 | 4 | 1 | 2 | 1 | 1 | 1 | 0 | 1 | 2 | 0 | 2 |
| 10850000 | 7500 | 3 | 3 | 1 | 1 | 0 | 1 | 0 | 1 | 2 | 1 | 1 |
| 10150000 | 8580 | 4 | 3 | 4 | 1 | 0 | 0 | 0 | 1 | 2 | 1 | 1 |
| 10150000 | 16200 | 5 | 3 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 9870000 | 8100 | 4 | 1 | 2 | 1 | 1 | 1 | 0 | 1 | 2 | 1 | 2 |
| 9800000 | 5750 | 3 | 2 | 4 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
Brakujące wartości wg. stanu umeblowania
agencja_nieruchomosci %>%
group_by(furnishingstatus) %>%
miss_var_summary() %>%
filter(n_miss > 0) %>%
knitr::kable()| furnishingstatus | variable | n_miss | pct_miss |
|---|---|---|---|
| 2 | price | 33 | 23.6 |
| 2 | prefarea | 15 | 10.7 |
| 2 | mainroad | 11 | 7.86 |
| 1 | price | 43 | 18.9 |
| 1 | mainroad | 23 | 10.1 |
| 1 | prefarea | 18 | 7.93 |
| 0 | price | 34 | 19.1 |
| 0 | prefarea | 17 | 9.55 |
| 0 | mainroad | 16 | 8.99 |
| n_miss_in_case | n_cases | pct_cases |
|---|---|---|
| 0 | 363 | 66.6055046 |
| 1 | 155 | 28.4403670 |
| 2 | 26 | 4.7706422 |
| 3 | 1 | 0.1834862 |
W tabeli podsumowującej widzimy, że liczba pustych pól na obserwację waha się od 0 do 7. Spośród 545 obserwacji 363 jest kompletnych - to 66,6% obserwacji w danych. Tylko 1 obserwacja (0,18%) zawiera 3 brakujące wartości.
Dzięki wykresom, które przedstawiają procent brakujących danych w zależności od filtru można wywnioskować, że największy procent brakujących danych jest zazwyczaj w momencie, gdzie jest najwieksza wartość dodatnia z konkretnych filtrów. Przykładowo największa ilość NA (price) jest w momencie, gdzie są 3 miejsca parkingowe.
Na powyższym wykresie widać, że najwięcej brakujących danych jest w kolumnie cena. Przyczyny są prawdopodobnie czysto praktycznie - za wysoka cena może odstraszyć potencjalnych klientów. Potencjalną przyczyną może oznaczać chęć zbierania ofert.
ggplot(data = agencja_nieruchomosci, aes(x = area, y = price)) +
geom_point() +
geom_miss_point() +
scale_color_manual(values = c("darkorange", "cyan4")) +
theme_minimal()W pierwszym przypadku widzimy, że brak wartości price był podobnie prawdopodobny do większości przypadków powierzchni domu. Można zauważyć brak NA w wielkości domu od 12 tys. do 16 tys. jednak są tam tylko pojedyncze wartości.
ggplot(data = agencja_nieruchomosci, aes(x = area, y = price)) +
geom_point() +
geom_miss_point() +
scale_color_manual(values = c("darkorange", "cyan4")) +
theme_minimal() +
facet_wrap(~bedrooms)W podziale na podwykresy widzimy, że najwięcej NA znajduje sie w nieruchomościach, które mają 3 sypialnie.
Identyfikacja brakujących danych jest kluczowym elementem czyszczenia datasetu. Kolejnym krokiem jest imputacja, czyli uzupełnienie brakujących komórek. Jest wiele metod umożliwiających imputację. Jedną z najpopularniejszych metod jest algorytm k najbliższych sąsiadów (kNN). Poniżej wykorzystano tę metodę to uzupełnienia brakujących cen. Niezbędnym jest tutaj określenie ilości sąsiadów (k) branych pod uwagę przy regresji, arbitralnie wybrana została wartość k=15.
agencja_nieruchomosci <- kNN(
agencja_nieruchomosci,
variable = "price",
k = 15
)
agencja_nieruchomosci <- subset(agencja_nieruchomosci, select = -price_imp)
knitr::kable(miss_var_summary(agencja_nieruchomosci))| variable | n_miss | pct_miss |
|---|---|---|
| mainroad | 50 | 9.17 |
| prefarea | 50 | 9.17 |
| price | 0 | 0 |
| area | 0 | 0 |
| bedrooms | 0 | 0 |
| bathrooms | 0 | 0 |
| stories | 0 | 0 |
| guestroom | 0 | 0 |
| basement | 0 | 0 |
| hotwaterheating | 0 | 0 |
| airconditioning | 0 | 0 |
| parking | 0 | 0 |
| furnishingstatus | 0 | 0 |
Kolejną znaną metodą jest imputacja liniowa. Zmienne brakujące w
kolumnie mainroad uzupełnione zostały wykorzystując metodę
impute_lm pochodzącą z pakietu simputation.
Wartości te imputujemy na podstawie zmiennych price oraz parking.
agencja_nieruchomosci <- impute_lm(
agencja_nieruchomosci,
variable = "mainroad",
formula = mainroad ~ price + parking,
)
agencja_nieruchomosci$mainroad <- round(agencja_nieruchomosci$mainroad)
knitr::kable(miss_var_summary(agencja_nieruchomosci))| variable | n_miss | pct_miss |
|---|---|---|
| prefarea | 50 | 9.17 |
| price | 0 | 0 |
| area | 0 | 0 |
| bedrooms | 0 | 0 |
| bathrooms | 0 | 0 |
| stories | 0 | 0 |
| mainroad | 0 | 0 |
| guestroom | 0 | 0 |
| basement | 0 | 0 |
| hotwaterheating | 0 | 0 |
| airconditioning | 0 | 0 |
| parking | 0 | 0 |
| furnishingstatus | 0 | 0 |
Dane w ostatniej brakującej kolumnie uzupełniamy metodą
mice czyli Multivariate Imputation by Chained Equations -
wielowymiarowe wypełnianie przez równania łańcuchowe. Jako że
uzupełniamy zmienną binarną, korzystamy z metody
logreg.
imputed_data <- mice(agencja_nieruchomosci, method = "logreg", m = 5, printFlag = FALSE)
completed_data <- complete(imputed_data, 1)
agencja_nieruchomosci <- completed_dataZobaczmy jak wygląda pierwsze 10 wierszy naszego zbioru danych po imputacji:
| price | area | bedrooms | bathrooms | stories | mainroad | guestroom | basement | hotwaterheating | airconditioning | parking | prefarea | furnishingstatus |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 7910000 | 7420 | 4 | 2 | 3 | 1 | 0 | 0 | 0 | 1 | 2 | 1 | 2 |
| 12250000 | 8960 | 4 | 4 | 4 | 1 | 0 | 0 | 0 | 1 | 3 | 0 | 2 |
| 12250000 | 9960 | 3 | 2 | 2 | 1 | 0 | 1 | 0 | 0 | 2 | 1 | 1 |
| 12215000 | 7500 | 4 | 2 | 2 | 1 | 0 | 1 | 0 | 1 | 3 | 1 | 2 |
| 11410000 | 7420 | 4 | 1 | 2 | 1 | 1 | 1 | 0 | 1 | 2 | 0 | 2 |
| 10850000 | 7500 | 3 | 3 | 1 | 1 | 0 | 1 | 0 | 1 | 2 | 1 | 1 |
| 10150000 | 8580 | 4 | 3 | 4 | 1 | 0 | 0 | 0 | 1 | 2 | 1 | 1 |
| 10150000 | 16200 | 5 | 3 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 9870000 | 8100 | 4 | 1 | 2 | 1 | 1 | 1 | 0 | 1 | 2 | 1 | 2 |
| 9800000 | 5750 | 3 | 2 | 4 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
## Transformacje
``` r
completed_data$price <- as.numeric(completed_data$price)
completed_data <- completed_data %>%
mutate(
price_z = (price - mean(price, na.rm = TRUE)) / sd(price, na.rm = TRUE),
price_minmax = scales::rescale(price, to = c(0, 1))
)
boxplot(completed_data$price_z, completed_data$price_minmax,
names = c("Z-score", "Min-max"), main = "Porównanie normalizacji danych")
skewness_results <- sapply(completed_data, function(x) if (is.numeric(x)) e1071::skewness(x, na.rm = TRUE) else NA)
knitr::kable(skewness_results)| x | |
|---|---|
| price | 1.2284480 |
| area | 1.3139246 |
| bedrooms | 0.4929587 |
| bathrooms | 1.5805260 |
| stories | 1.0761391 |
| mainroad | -2.2903089 |
| guestroom | 1.6791359 |
| basement | 0.6251337 |
| hotwaterheating | 4.3294938 |
| airconditioning | 0.7913726 |
| parking | 0.8374328 |
| prefarea | 1.2236374 |
| furnishingstatus | 0.1170196 |
| price_z | 1.2284480 |
| price_minmax | 1.2284480 |
| variables | outliers_cnt | outliers_ratio | outliers_mean | with_mean | without_mean |
|---|---|---|---|---|---|
| price | 13 | 2.3853211 | 1.053123e+07 | 4.721686e+06 | 4.579723e+06 |
| area | 12 | 2.2018349 | 1.269325e+04 | 5.150541e+03 | 4.980724e+03 |
| bedrooms | 12 | 2.2018349 | 5.166667e+00 | 2.965138e+00 | 2.915572e+00 |
| bathrooms | 1 | 0.1834862 | 4.000000e+00 | 1.286239e+00 | 1.281250e+00 |
| stories | 41 | 7.5229358 | 4.000000e+00 | 1.805505e+00 | 1.626984e+00 |
| mainroad | 67 | 12.2935780 | 0.000000e+00 | 8.770642e-01 | 1.000000e+00 |
| guestroom | 97 | 17.7981651 | 1.000000e+00 | 1.779817e-01 | 0.000000e+00 |
| basement | 0 | 0.0000000 | NaN | 3.504587e-01 | 3.504587e-01 |
| hotwaterheating | 25 | 4.5871560 | 1.000000e+00 | 4.587160e-02 | 0.000000e+00 |
| airconditioning | 0 | 0.0000000 | NaN | 3.155963e-01 | 3.155963e-01 |
| parking | 12 | 2.2018349 | 3.000000e+00 | 6.935780e-01 | 6.416510e-01 |
| prefarea | 130 | 23.8532110 | 1.000000e+00 | 2.385321e-01 | 0.000000e+00 |
| furnishingstatus | 0 | 0.0000000 | NaN | 9.302752e-01 | 9.302752e-01 |
| price_z | 13 | 2.3853211 | 3.269696e+00 | 0.000000e+00 | -7.989860e-02 |
| price_minmax | 13 | 2.3853211 | 8.363077e-01 | 2.830177e-01 | 2.694975e-01 |
dane <- (agencja_nieruchomosci)
Q1 <- quantile(dane$stories, 0.25, na.rm = TRUE)
Q3 <- quantile(dane$stories, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
outliers <- dane$stories[dane$stories < lower_bound | dane$stories > upper_bound]
boxplot(dane$stories, main = "Wartości odstające w zmiennej 'stories'",
col = "lightblue", horizontal = TRUE)dane_cleaned <- dane %>%
filter(stories >= lower_bound, stories <= upper_bound)
boxplot(dane_cleaned$stories, main = "wykres pudełkowy dla zmiennej 'stories' bez wartości odstających",
col = "lightblue", horizontal = TRUE)Wykres pudełkowy dla zmiennej “stories” bez wartości odstających - został nałożony filtr nieuwzględniający wartości odstających.
completed_data$price <- completed_data$price / 1000
completed_data$area <- completed_data$area * 0.092903
ggplot(completed_data, aes(x=price))+
geom_histogram(bins = 10)+
labs(title="Ilośc domów z przedziałami cenowymi", x="Price", y="Ilość domów")+
theme_bw() +
facet_grid(~parking)completed_data$bedfac <- as.factor(completed_data$bedrooms)
ggplot(completed_data, aes(x = area, y = price, color = bedfac)) +
geom_point(alpha = 0.7, size = 3) +
scale_color_brewer(palette = "Set1") +
theme_ipsum() +
facet_grid(~mainroad) +
labs(
x = "Wielkość domu",
y = "Cena",
color = "Liczba sypialni")+
theme( text = element_text(family = "sans"))ggplot(completed_data, aes(x = bedrooms, y = price, color = bedfac)) +
geom_point(alpha = 0.7, size = 3) +
scale_color_brewer(palette = "Set1") +
theme_ipsum() +
theme(
text = element_text(family = "sans") ## Użyj czcionki sans
) +
facet_grid(~prefarea) +
labs(
x = "ilość sypialni",
y = "Cena",
color = "Liczba sypialni"
)completed_data$prefarea1 <- as.factor(completed_data$prefarea) ## Zamiana na factor
p <- ggplot(completed_data, aes(x = price, y = area)) +
geom_point(aes(color = prefarea1)) +
geom_smooth(method = "lm", se = TRUE)+
xlab("Cena")+
ylab("Powierzchnia domu")+
scale_color_discrete(name = "Preferowane miejsce")+
ggtitle("Metraż oraz cena domu")+
theme_light()
plotly::ggplotly(p)completed_data$pietra <- as.factor(completed_data$stories)
ggplot(completed_data, aes(x = stories, y = area)) +
geom_boxplot(aes(group = stories), outlier.shape = NA) +
geom_jitter(aes(color = price), width = 0.2, alpha = 0.7) +
scale_color_gradient(name = "Cena", low = "lightblue", high = "navyblue") +
xlab("Liczba pięter") +
ylab("Powierzchnia domu") +
ggtitle("Rozkład powierzchni domu w zależności od liczby pięter i ceny") +
theme_minimal()summary_table <- completed_data %>%
group_by(pietra) %>%
summarise(
Srednia_powierzchnia = mean(area, na.rm = TRUE),
Mediana_powierzchnia = median(area, na.rm = TRUE),
Std_powierzchnia = sd(area, na.rm = TRUE),
Srednia_cena = mean(price, na.rm = TRUE),
Mediana_cena = median(price, na.rm = TRUE),
Std_cena = sd(price, na.rm = TRUE),
Liczba_obserwacji = n()
)
knitr::kable(summary_table)| pietra | Srednia_powierzchnia | Mediana_powierzchnia | Std_powierzchnia | Srednia_cena | Mediana_cena | Std_cena | Liczba_obserwacji |
|---|---|---|---|---|---|---|---|
| 1 | 491.4405 | 418.0635 | 211.4452 | 4155.658 | 3815 | 1367.579 | 227 |
| 2 | 441.9345 | 386.9410 | 197.1835 | 4723.147 | 4200 | 1841.284 | 238 |
| 3 | 493.9319 | 510.9665 | 183.7000 | 5451.385 | 5810 | 1289.063 | 39 |
| 4 | 604.4428 | 557.4180 | 111.2456 | 7152.962 | 7245 | 1518.262 | 41 |
mean_price <- mean(completed_data$price)
sd_price <- sd(completed_data$price)
completed_data$z_score <- (completed_data$price - mean_price) / sd_price
completed_data$price_category <- cut(
completed_data$z_score,
breaks = c(-Inf, -1, 1, Inf),
labels = c("tanie", "średnie", "drogie")
)
category_counts <- completed_data %>%
group_by(price_category) %>%
summarise(count = n())Wykres przedstawia ceny nieruchomości, które należą do agencji nieruchomości. Poprzez stworzenie 3 znaczników - tani, średni, drogi możemy przeanalizować w jaki sposób plasują się ceny z bazy danych.
ggplot(category_counts) +
aes(
x0 = 0, y0 = 0,
r0 = 0, r = 1,
amount = count,
fill = price_category
) +
geom_arc_bar(stat = "pie") +
coord_fixed()etykiety<-c("1750-2750 kPLN","2750-3750 kPLN","3750-4750 kPLN","4750-5750 kPLN","5750-6750 kPLN","6750-7750 kPLN","7750-8750 kPLN","9750-10750 kPLN","10750-11750 kPLN","11750-12250 kPLN")
limits<-cut(completed_data$price,seq(1750,12250,by=1000),labels=etykiety)
tabela1<-freq(limits)
knitr::kable(tabela1)| n | % | val% | |
|---|---|---|---|
| 1750-2750 kPLN | 35 | 6.4 | 6.5 |
| 2750-3750 kPLN | 145 | 26.6 | 26.9 |
| 3750-4750 kPLN | 146 | 26.8 | 27.1 |
| 4750-5750 kPLN | 87 | 16.0 | 16.1 |
| 5750-6750 kPLN | 66 | 12.1 | 12.2 |
| 6750-7750 kPLN | 24 | 4.4 | 4.5 |
| 7750-8750 kPLN | 21 | 3.9 | 3.9 |
| 9750-10750 kPLN | 8 | 1.5 | 1.5 |
| 10750-11750 kPLN | 5 | 0.9 | 0.9 |
| 11750-12250 kPLN | 2 | 0.4 | 0.4 |
| NA | 6 | 1.1 | NA |
Poniższy wykres kolumnowy przedstawia rozkład cen mieszkań z podziałem co 1000. Można wywnioskować, iż tak jak na wykresie kołowym, większość mieszkań jest blisko średniej ceny rynkowej. Tańsze mieszkania oraz droższe są w zdecydowanej mniejszości. Dodatkowo zaznaczono liniami jak kształtują się ceny mieszkań w podziale na ilość sypialni.
hist(completed_data$price, breaks="FD", col="green", probability = TRUE,
main="Ceny nieruchomości")
lines(density(completed_data$price[completed_data$bedrooms == 1]), col=2)
lines(density(completed_data$price[completed_data$bedrooms == 2]), col=3)
lines(density(completed_data$price[completed_data$bedrooms == 3]), col=4)
legend("topright",
legend=c("Jedna sypialnia", "Dwie sypialnie", "Trzy sypialnie"),
col=c(2, 3, 4),
lty=1,
horiz=FALSE,
box.lty=0,
cex=0.8)completed_data %>%
select(price, bedfac) %>%
tbl_summary(
by=bedfac,
type = all_continuous() ~ "continuous2",
statistic = all_continuous() ~ c(
"{N_nonmiss}","{mean}","{sd}",
"{median} ({p25}, {p75})",
"{min}, {max}"),
missing = "no",
label = price ~ "Cena") %>%
modify_header(label ~ "**Zmienna**") %>%
modify_caption("**Tabela 1. Rozkład cen wg liczby pokoi**") %>%
bold_labels() %>%
add_p(pvalue_fun = ~ style_pvalue(.x, digits = 2))| Zmienna | 1 N = 2 |
2 N = 136 |
3 N = 300 |
4 N = 95 |
5 N = 10 |
6 N = 2 |
p-value |
|---|---|---|---|---|---|---|---|
| Cena | |||||||
| N Non-missing | 2 | 136 | 300 | 95 | 10 | 2 | |
| Mean | 2,713 | 3,647 | 4,919 | 5,551 | 5,925 | 4,792 | |
| SD | 619 | 990 | 1,678 | 2,147 | 2,339 | 1,826 | |
| Median (Q1, Q3) | 2,713 (2,275, 3,150) | 3,500 (2,951, 4,200) | 4,550 (3,640, 5,950) | 5,250 (4,060, 6,300) | 5,583 (3,850, 8,120) | 4,792 (3,500, 6,083) | |
| Min, Max | 2,275, 3,150 | 1,750, 7,070 | 1,750, 12,250 | 2,100, 12,250 | 3,010, 10,150 | 3,500, 6,083 |
Podstawowe statystyki opisowe cen nieruchomości jeżeli znajdują się w preferowanym obszarze (tak/nie - 1/0). Dla obu przypadków są widoczne obserwacje odstające dla zmiennej price. Mediana cen nieruchomości dla tych znajdujących się w preferowanej okolicy jest większa. W bazie więcej jest nieruchomości, które nie znajdują sie w preferowanej okolicy. W przypadku nieruchomości nieznajdujących się w preferowanym obszarze, pierwsza część obserwacji ma większe zagęszczenie przy niskiej cenie 2 - 4 tys., a ceny nad medianą mają większą rozpiętość - od około 4 do 12 tys. Dla nieruchomości w preferowanym obszarze wiolina jest najszersza w okolicach mediany - najwięcej obserwacji kiedy cena jest bliska wartości środkowej - około 6 tys.
data(completed_data)
completed_data %>%
filter(prefarea %in% c(0, 1))%>%
ggbetweenstats(
y=price,
x=prefarea
)
## Wykres kołowy Jaki procent nieruchomości o powierzchni z danego
przedziału posiada posiada wskazaną liczbę łazienek. Nawet w domach o
największej powierzni jest tylko jedna łazienka.
completed_data$area_category <- cut(
completed_data$area,
breaks = c(0, 2000, 5000, 10000, 16200),
labels = c("0-2000", "2001-5000", "5001-10000", "10001-1620"),
right = TRUE
)
completed_data %>%
filter(bathrooms %in% c(1, 2 ,3, 4))%>%
ggpiestats(
y=area_category,
x=bathrooms
)Korelogram przedstawiający korelację pomiędzy zmiennymi dla domów z dwoma i sześcioma sypialniami z podziałem na dwie grupy - czy znajdują się przy głównej ulicy (1), czy nie (0).
grouped_ggcorrmat(
data = dplyr::filter(completed_data, bedrooms %in% c(2,6)),
type = "robust",
colors = c("#cbac43", "white", "#550000"),
grouping.var = mainroad,
matrix.type = "lower"
)Raport przedstawia kompleksową analizę danych dotyczących nieruchomości, koncentrując się na brakujących wartościach, czyszczeniu danych oraz metodach imputacji. Dane zostały poddane weryfikacji pod kątem błędów logicznych i spójności, a następnie przekształcone w celu ułatwienia dalszej analizy. Kluczowe wnioski:
Podjęte kroki znacząco poprawiły jakość danych i umożliwiły bardziej rzetelną analizę rynku nieruchomości. Zastosowane metody przetwarzania i imputacji danych pozwalają na dalsze wykorzystanie zbioru do prognozowania cen oraz analizy trendów rynkowych. W niniejszyn raporcie skupiono się na technicznych aspektach analizy danych, kolejnym krokiem mogłaby być bardziej zaawansowana analiza statystyczna, np. modelowanie regresyjne czy klasyfikacja, co pozwoliłoby na jeszcze głębsze zrozumienie rynku nieruchomości. Wturnym i mniej poruszonym zagadnieniem była sama formalna analiza opisowa danych.